﻿using System;
using System.Collections.ObjectModel;
using Microsoft.Xna.Framework.Resources;

namespace Microsoft.Xna.Framework
{
    /// <summary>
    /// 	A collection of game components.
    /// </summary>
    public sealed class GameComponentCollection : Collection<IGameComponent>
    {
        #region Events

        /// <summary>
        /// 	Raised when a component is added to the GameComponentCollection.
        /// </summary>
        public event EventHandler<GameComponentCollectionEventArgs> ComponentAdded;

        private void OnComponentAdded(GameComponentCollectionEventArgs eventArgs)
        {
            var onComponentAdded = ComponentAdded;
            if (onComponentAdded != null)
            {
                onComponentAdded(this, eventArgs);
            }
        }

        /// <summary>
        /// 	Raised when a component is removed from the GameComponentCollection.
        /// </summary>
        public event EventHandler<GameComponentCollectionEventArgs> ComponentRemoved;

        private void OnComponentRemoved(GameComponentCollectionEventArgs eventArgs)
        {
            var onComponentRemoved = ComponentRemoved;
            if (onComponentRemoved != null)
            {
                onComponentRemoved(this, eventArgs);
            }
        }

        #endregion

        #region Overrides of Collection<IGameComponent>

        /// <summary>
        /// 	Removes all elements from the <see cref = "T:System.Collections.ObjectModel.Collection`1" />.
        /// </summary>
        protected override void ClearItems()
        {
            for (var index = 0; index < Count; index++)
            {
                OnComponentRemoved(new GameComponentCollectionEventArgs(base[index]));
            }
            base.ClearItems();
        }

        /// <summary>
        /// 	Inserts an element into the <see cref = "T:System.Collections.ObjectModel.Collection`1" /> at the specified index.
        /// </summary>
        /// <param name = "index">The zero-based index at which <paramref name = "item" /> should be inserted.</param>
        /// <param name = "item">The object to insert. The value can be null for reference types.</param>
        /// <exception cref = "T:System.ArgumentOutOfRangeException"><paramref name = "index" /> is less than zero.-or-<paramref
        /// 	name = "index" /> is greater than <see cref = "P:System.Collections.ObjectModel.Collection`1.Count" />.</exception>
        protected override void InsertItem(int index, IGameComponent item)
        {
            if (IndexOf(item) != -1)
            {
                throw new ArgumentException(Resx.CannotAddSameComponentMultipleTimes);
            }
            base.InsertItem(index, item);
            if (item != null)
            {
                OnComponentAdded(new GameComponentCollectionEventArgs(item));
            }
        }

        /// <summary>
        /// 	Removes the element at the specified index of the <see cref = "T:System.Collections.ObjectModel.Collection`1" />.
        /// </summary>
        /// <param name = "index">The zero-based index of the element to remove.</param>
        /// <exception cref = "T:System.ArgumentOutOfRangeException"><paramref name = "index" /> is less than zero.-or-<paramref
        /// 	name = "index" /> is equal to or greater than <see cref = "P:System.Collections.ObjectModel.Collection`1.Count" />.</exception>
        protected override void RemoveItem(int index)
        {
            var item = base[index];
            base.RemoveItem(index);
            if (item != null)
            {
                OnComponentRemoved(new GameComponentCollectionEventArgs(item));
            }
        }

        /// <summary>
        /// 	Replaces the element at the specified index.
        /// </summary>
        /// <param name = "index">The zero-based index of the element to replace.</param>
        /// <param name = "item">The new value for the element at the specified index. The value can be null for reference types.</param>
        /// <exception cref = "T:System.ArgumentOutOfRangeException"><paramref name = "index" /> is less than zero.-or-<paramref
        /// 	name = "index" /> is greater than <see cref = "P:System.Collections.ObjectModel.Collection`1.Count" />.</exception>
        protected override void SetItem(int index, IGameComponent item)
        {
            throw new NotSupportedException(Resx.CannotSetItemsIntoGameComponentCollection);
        }

        #endregion
    }
}